package com.sluggard.security.core.handler;

import com.sluggard.common.exception.BusinessException;
import com.sluggard.common.model.res.Result;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.http.HttpStatus;
import org.springframework.http.converter.HttpMessageNotReadableException;
import org.springframework.security.access.AccessDeniedException;
import org.springframework.security.authentication.BadCredentialsException;
import org.springframework.validation.BindException;
import org.springframework.web.HttpMediaTypeNotSupportedException;
import org.springframework.web.bind.MethodArgumentNotValidException;
import org.springframework.web.bind.MissingServletRequestParameterException;
import org.springframework.web.bind.annotation.ExceptionHandler;
import org.springframework.web.bind.annotation.RestControllerAdvice;
import org.springframework.web.method.annotation.MethodArgumentTypeMismatchException;
import org.springframework.web.servlet.NoHandlerFoundException;
import org.springframework.web.servlet.resource.NoResourceFoundException;

import java.util.stream.Collectors;


/**
 * @author lizheng
 */
@Slf4j
@RestControllerAdvice
public class GlobalExceptionHandler {

    @ExceptionHandler(MissingServletRequestParameterException.class)
    public Result<Void> params(MissingServletRequestParameterException e) {
        return Result.error(HttpServletResponse.SC_BAD_REQUEST, e.getParameterName() + "：缺少参数");
    }

    @ExceptionHandler(MethodArgumentTypeMismatchException.class)
    public Result<Void> type(MethodArgumentTypeMismatchException e) {
        return Result.error(HttpServletResponse.SC_BAD_REQUEST, e.getParameter().getParameterName() + "：参数类型错误");
    }

    @ExceptionHandler(HttpMediaTypeNotSupportedException.class)
    public Result<Void> httpType(HttpMediaTypeNotSupportedException e) {
        return Result.error(HttpServletResponse.SC_BAD_REQUEST, "HTTP类型不支持");
    }

    @ExceptionHandler(HttpMessageNotReadableException.class)
    public Result<Void> http(HttpMessageNotReadableException e) {
        return Result.error(HttpServletResponse.SC_BAD_REQUEST, e.getMessage());
    }


    @ExceptionHandler(BindException.class)
    public Result<Void> bind(BindException e) {
        return Result.error(HttpServletResponse.SC_BAD_REQUEST, e.getFieldErrors()
                .stream()
                .map(err -> err.getField() + "：" + err.getRejectedValue() + " " + err.getDefaultMessage())
                .collect(Collectors.joining("<br>")));
    }

    /**
     * 参数验证不通过
     *
     * @param e
     * @return
     */
    @ExceptionHandler(MethodArgumentNotValidException.class)
    public Result<Void> valid(MethodArgumentNotValidException e) {
        return Result.error(HttpServletResponse.SC_BAD_REQUEST, e.getFieldErrors()
                .stream()
                .map(err -> err.getField() + "：" + err.getRejectedValue() + " " + err.getDefaultMessage())
                .collect(Collectors.joining("<br>")));
    }

    @ExceptionHandler(Exception.class)
    public Result<Void> globalException(HttpServletRequest request, Throwable ex) {
        if (!(ex instanceof BusinessException)) {
            log.error("全局异常", ex);
        }
        return Result.error(getStatus(request).value(), ex.getMessage());
    }


    @ExceptionHandler({BadCredentialsException.class})
    public Result<Void> loginError(BadCredentialsException e) {
        return Result.error(e.getMessage());
    }


    @ExceptionHandler({AccessDeniedException.class})
    public Result<Void> accessDenied(AccessDeniedException e) {
        return Result.error(HttpStatus.FORBIDDEN.value(), "无访问权限");
    }

    private HttpStatus getStatus(HttpServletRequest request) {
        Integer statusCode = (Integer) request.getAttribute("javax.servlet.error.status_code");
        if (statusCode == null) {
            return HttpStatus.INTERNAL_SERVER_ERROR;
        }
        return HttpStatus.valueOf(statusCode);
    }
}

